class MyVue {
  // 1.代理数据和数据劫持
  // 2.初始化dom数据使`v-if/v-show/@click`和dom绑定在一起
  // 3.初始化视图，根据`data`数据先初始化时候显示视图组件
  // 4.根据事件池去做时间处理函数的循环绑定
  // 5.改变数据的同时改变dom视图

  constructor(options) {
    const { el, data, methods } = options;
    this.el = document.querySelector(el);
    this.data = data;
    this.methods = methods;

    //定义池子
    this.showPool = new Map();
    this.eventPool = new Map();

    // console.log(this.el);
    //<div id="app">...</div>

    // console.log(this.data);
    //{boxShow1: false, boxShow2: false, boxShow3: false, boxShow4: false}

    // console.log(this.methods);
    //{boxShow1: ƒ, boxShow2: ƒ, boxShow3: ƒ, boxShow4: ƒ}

    this.init();
    console.log(this);
  }

  init() {
    // 1.代理数据和数据劫持
    this.initData();
    // 2.初始化dom数据使`v-if/v-show/@click`和dom绑定在一起
    this.initDom(this.el);
    // 3.初始化视图，根据`data`数据先初始化时候显示视图组件
    this.initView(null, this.showPool);
    // 4.根据事件池去做时间处理函数的循环绑定
    this.initEvent(this.eventPool);
  }

  initData() {
    for (let key in this.data) {
      // console.log(key);
      //boxShow1/boxShow2/boxShow3/boxShow4

      Object.defineProperty(this, key, {
        //访问this.boxShow1 -> this.data.boxShow1
        get() {
          return this.data[key];
        },
        //修改this.boxShow1 = true -> this.data.boxShow1 = true
        set(newValue) {
          this.data[key] = newValue;

          //数据劫持实现数据更改使得视图更新
          this.domChange(key, this.showPool);
        },
      });
    }
  }

  initDom(el) {
    //获取el的子节点
    const _childNodes = el.childNodes;
    // console.log(_childNodes);
    //NodeList(11) [text, div.box-wrapper, text, button, text, button, text, button, text, button, text]

    //没有子节点时
    if (!_childNodes.length) {
      //中止程序向下运行
      return;
    }

    //树型结构需要递归处理
    _childNodes.forEach((dom) => {
      // console.log(dom);
      //#text
      //<div class="box-wrapper">...</div>
      //#text
      //<button @click="showBox1">BOX 1</button>
      //#text
      //<button @click="showBox2">BOX 2</button>
      //#text
      //...

      //当子节点是元素节点时
      if (dom.nodeType === 1) {
        const vIf = dom.getAttribute("v-if");
        const vShow = dom.getAttribute("v-show");
        const vEvent = dom.getAttribute("@click");

        //当v-if节点存在时
        if (vIf) {
          //将当前节点保存到showPool池里
          this.showPool.set(dom, {
            type: "if",
            //this.data[vIf] -> boxShow1 -> false
            show: this.data[vIf],
            //vIf -> true/false
            data: vIf,
          });
        } else if (vShow) {
          //当v-show节点存在时
          //将当前节点保存到showPool池里
          this.showPool.set(dom, {
            type: "show",
            show: this.data[vShow],
            //vShow -> true/false
            data: vShow,
          });
        }

        //当@click节点存在时
        if (vEvent) {
          //将当前节点保存到showPool池里

          // console.log(vEvent);
          //showBox1/showBox2/showBox3/showBox4

          //this.methods[vEvent] -> this.methods[showBox1]
          // console.log(this.methods[vEvent]);
          this.eventPool.set(dom, this.methods[vEvent]);
        }
      }

      //递归嵌套的子层
      this.initDom(dom);

      /**
       * console.log(this.showPool);
       * Map(4) {
       *   div.box.box1 => {
       *     key: div.box.box1,
       *     value: {type: 'if', show: false, data: 'boxShow1'}
       *   },
       *   div.box.box2 => {…},
       *   div.box.box3 => {…},
       *   div.box.box4 => {…}
       * }
       */

      /**
       * console.log(this.eventPool);
       * Map(4) {
       *   {
       *     key: button,
       *     value: ƒ showBox1()
       *   },
       *   button => ƒ,
       *   button => ƒ,
       *   button => ƒ
       * }
       */
    });
  }

  initView(nu, showPool) {
    this.domChange(nu, showPool);
  }

  initEvent(eventPool) {
    for (let [k, v] of eventPool) {
      // console.log(k);
      //<button @click="showBox1">BOX 1</button>

      // console.log(v);
      //ƒ showBox1() {this.boxShow1 = !this.boxShow1;}

      //给当前节点绑定事件处理函数
      k.addEventListener("click", v.bind(this), false);
    }
  }

  /**
   * 根据data数据去更改dom
   * @param {*} data boxShow1/boxShow2/boxShow3/boxShow4
   * @param {*} showPool
   */
  domChange(data, showPool) {
    //首次更改数据时
    if (!data) {
      for (let [k, v] of showPool) {
        // console.log(k);
        //<div class="box box1" v-if="boxShow1">BOX1</div>

        // console.log(v);
        //{type: 'if', show: false, data: 'boxShow1'}

        //判断类型
        switch (v.type) {
          case "if":
            //增加注释节点实现占位
            //保证删除后的节点找到之前的位置
            v.comment = document.createComment("v-if");
            // console.log(v);
            //{type: 'if', show: false, data: 'boxShow1', comment: comment}

            //当data里boxShow1: false时替换当前节点为注释节点<!--v-if-->
            if (!v.show) {
              //replaceChild(新节点，旧节点)
              //替换新老节点
              k.parentNode.replaceChild(v.comment, k);
            }
            break;
          case "show":
            //当data里boxShow1: false时 隐藏该节点，默认显示
            if (!v.show) {
              //将当前节点的样式改为隐藏
              k.style.display = "none";
            }
            break;
          default:
            break;
        }
      }
      return;
    }

    //再次更改数据时
    for (let [k, v] of showPool) {
      // console.log(v.data);
      //boxShow1/boxShow2/boxShow3/boxShow4

      // console.log(data);
      //点击按钮显示的boxShow1

      //当循环到的data和点击的data一致时
      if (v.data === data) {
        switch (v.type) {
          case "if":
            //点击切换替换当前节点为注释节点
            v.show
              ? k.parentNode.replaceChild(v.comment, k)
              : v.comment.parentNode.replaceChild(k, v.comment);
            v.show = !v.show;
            break;
          case "show":
            //点击切换显示或隐藏当前节点
            v.show ? (k.style.display = "none") : (k.style.display = "block");
            v.show = !v.show;
            break;
          default:
            break;
        }
      }
    }
  }
}

export default MyVue;

/**
 * showPool: [
 *   [
 *     dom,
 *     {
 *       //如果是if则需要增删节点
 *       type: if / show,
 *       //如果是show则需要显示或隐藏
 *       show: true / false,
 *       data: 绑定的数据
 *     }
 *   ]
 * ]
 */

/**
 * eventPool: [
 *   [
 *     dom,
 *     handler
 *   ]
 * ]
 */
